#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
安卓UI预览工具
通过ADB获取安卓界面截图并展示当前XML标记、单个元素的全部信息
方便编写AutoJS脚本代码
"""

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import subprocess
import os
import json
import xml.etree.ElementTree as ET
from PIL import Image, ImageTk
import threading
import time
import re
from datetime import datetime
import adb_helper
from adb_helper import ADBNotFoundError

class AndroidUIExplorer:
    def __init__(self, root, adb_path=None):
        self.root = root
        self.root.title("安卓UI预览工具 - Android UI Explorer")
        self.root.geometry("1400x900")
        self.root.configure(bg='#f0f0f0')
        
        # 设置窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 设备信息
        self.devices = []
        self.current_device = None
        self.screenshot_path = "screenshot.png"
        self.xml_path = "ui.xml"
        
        # ADB辅助
        self.adb = adb_helper.ADBHelper(adb_path)
        
        # UI元素信息
        self.current_elements = []
        self.selected_element = None
        
        self.setup_ui()
        self.refresh_devices()
        
    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 顶部控制面板
        control_frame = ttk.LabelFrame(main_frame, text="设备控制", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 设备选择
        device_frame = ttk.Frame(control_frame)
        device_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(device_frame, text="设备:").pack(side=tk.LEFT)
        self.device_var = tk.StringVar()
        self.device_combo = ttk.Combobox(device_frame, textvariable=self.device_var, width=40)
        self.device_combo.pack(side=tk.LEFT, padx=(5, 10))
        self.device_combo.bind("<<ComboboxSelected>>", self.on_device_select)
        
        ttk.Button(device_frame, text="刷新设备", command=self.refresh_devices).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(device_frame, text="刷新界面", command=self.refresh_ui).pack(side=tk.LEFT)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(control_frame, textvariable=self.status_var, foreground="blue")
        status_label.pack(anchor=tk.W)
        
        # 主要内容区域 - 使用一个PanedWindow实现三栏布局
        p_main = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        p_main.pack(fill=tk.BOTH, expand=True)

        # --- Column 1: Screenshot ---
        left_frame = ttk.LabelFrame(p_main, text="界面截图", padding=10)
        p_main.add(left_frame, weight=1)

        # 截图画布
        self.canvas_frame = ttk.Frame(left_frame)
        self.canvas_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建画布和滚动条
        self.canvas = tk.Canvas(self.canvas_frame, bg="white", cursor="cross")
        
        # 创建滚动条
        v_scrollbar = ttk.Scrollbar(self.canvas_frame, orient=tk.VERTICAL, command=self.canvas.yview)
        h_scrollbar = ttk.Scrollbar(self.canvas_frame, orient=tk.HORIZONTAL, command=self.canvas.xview)
        
        # 配置画布的滚动
        self.canvas.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set)
        
        # 使用grid布局来正确放置画布和滚动条
        self.canvas.grid(row=0, column=0, sticky="nsew")
        v_scrollbar.grid(row=0, column=1, sticky="ns")
        h_scrollbar.grid(row=1, column=0, sticky="ew")
        
        # 配置grid权重
        self.canvas_frame.grid_rowconfigure(0, weight=1)
        self.canvas_frame.grid_columnconfigure(0, weight=1)
        
        self.canvas.bind("<Button-1>", self.on_canvas_click)
        self.canvas.bind("<Motion>", self.on_canvas_motion)

        # --- Column 2: Element Tree ---
        middle_frame = ttk.LabelFrame(p_main, text="界面元素树", padding=10)
        p_main.add(middle_frame, weight=1)
        
        tree_frame = ttk.Frame(middle_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建树形视图和滚动条
        self.elements_tree = ttk.Treeview(tree_frame)
        h_tree_scrollbar = ttk.Scrollbar(tree_frame, orient=tk.HORIZONTAL, command=self.elements_tree.xview)
        v_tree_scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=self.elements_tree.yview)
        
        # 配置树形视图的滚动
        self.elements_tree.configure(yscrollcommand=v_tree_scrollbar.set, xscrollcommand=h_tree_scrollbar.set)
        
        # 配置#0列（树列）
        self.elements_tree.heading("#0", text="元素层级", anchor='w')
        self.elements_tree.column("#0", anchor="w", minwidth=200, width=550)

        # 使用grid布局来正确放置树形视图和滚动条
        self.elements_tree.grid(row=0, column=0, sticky="nsew")
        v_tree_scrollbar.grid(row=0, column=1, sticky="ns")
        h_tree_scrollbar.grid(row=1, column=0, sticky="ew")
        
        # 配置grid权重
        tree_frame.grid_rowconfigure(0, weight=1)
        tree_frame.grid_columnconfigure(0, weight=1)
        
        self.elements_tree.bind("<<TreeviewSelect>>", self.on_tree_select)

        # --- Column 3: Details & Code ---
        right_most_frame = ttk.Frame(p_main)
        p_main.add(right_most_frame, weight=1)

        # 元素详情
        details_frame = ttk.LabelFrame(right_most_frame, text="元素详情", padding=10)
        details_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        self.details_text = tk.Text(details_frame, width=50, height=10, wrap=tk.WORD)
        details_scrollbar = ttk.Scrollbar(details_frame, orient=tk.VERTICAL, command=self.details_text.yview)
        self.details_text.configure(yscrollcommand=details_scrollbar.set)
        
        self.details_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        details_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # AutoJS代码生成
        autojs_frame = ttk.LabelFrame(right_most_frame, text="AutoJS代码", padding=10)
        autojs_frame.pack(fill=tk.BOTH, expand=True)
        
        self.autojs_text = tk.Text(autojs_frame, width=50, height=8, wrap=tk.WORD)
        autojs_scrollbar = ttk.Scrollbar(autojs_frame, orient=tk.VERTICAL, command=self.autojs_text.yview)
        self.autojs_text.configure(yscrollcommand=autojs_scrollbar.set)
        
        self.autojs_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        autojs_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 底部按钮
        button_frame = ttk.Frame(right_most_frame)
        button_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=(10, 0))
        
        ttk.Button(button_frame, text="复制AutoJS代码", command=self.copy_autojs_code).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(button_frame, text="保存截图", command=self.save_screenshot).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(button_frame, text="导出XML", command=self.export_xml).pack(side=tk.LEFT)
        
    def refresh_devices(self):
        """刷新设备列表"""
        try:
            self.status_var.set("正在获取设备列表...")
            self.root.update()
            devices = self.adb.get_devices()
            self.devices = devices
            self.device_combo['values'] = self.devices
            if self.devices:
                self.device_combo.set(self.devices[0])
                self.current_device = self.devices[0]
                # 同时设置ADBHelper的当前设备
                self.adb.set_device(self.current_device)
                self.status_var.set(f"找到 {len(self.devices)} 个设备")
            else:
                self.status_var.set("未找到设备，请检查ADB连接")
        except ADBNotFoundError as e:
            self.status_var.set("未找到ADB工具")
            messagebox.showerror("错误", f"未找到ADB工具，请等待下载完成或重启应用。\n{e}")
        except Exception as e:
            self.status_var.set(f"获取设备失败: {str(e)}")
            messagebox.showerror("错误", f"获取设备列表失败:\n{str(e)}")
    
    def capture_screenshot(self):
        """获取设备截图"""
        if not self.current_device:
            messagebox.showwarning("警告", "请先选择设备")
            return
            
        try:
            self.status_var.set("正在获取截图...")
            self.root.update()
            
            # 使用ADB获取截图
            success = self.adb.capture_screenshot(self.screenshot_path)
            if success:
                # 显示截图
                self.display_screenshot()
                self.status_var.set("截图获取成功")
            else:
                self.status_var.set("截图获取失败")
                messagebox.showerror("错误", "获取截图失败")
            
        except ADBNotFoundError as e:
            self.status_var.set("未找到ADB工具")
            messagebox.showerror("错误", f"未找到ADB工具，请等待下载完成或重启应用。\n{e}")
        except Exception as e:
            self.status_var.set(f"截图失败: {str(e)}")
            messagebox.showerror("错误", f"获取截图失败:\n{str(e)}")
    
    def get_xml(self):
        """获取当前界面的XML布局"""
        if not self.current_device:
            messagebox.showwarning("警告", "请先选择设备")
            return
            
        try:
            self.status_var.set("正在获取XML布局...")
            self.root.update()
            
            # 获取当前界面的XML
            success = self.adb.get_ui_xml(self.xml_path)
            if success:
                # 解析XML并构建树
                self.parse_xml()
                self.status_var.set("XML获取和解析成功")
            else:
                self.status_var.set("XML获取失败")
                messagebox.showerror("错误", "获取XML失败")
            
        except ADBNotFoundError as e:
            self.status_var.set("未找到ADB工具")
            messagebox.showerror("错误", f"未找到ADB工具，请等待下载完成或重启应用。\n{e}")
        except Exception as e:
            self.status_var.set(f"XML获取失败: {str(e)}")
            messagebox.showerror("错误", f"获取XML失败:\n{str(e)}")
    
    def parse_xml(self):
        """解析XML文件并直接构建树形结构"""
        try:
            tree = ET.parse(self.xml_path)
            root = tree.getroot()
            
            # 清空旧数据
            self.elements_tree.delete(*self.elements_tree.get_children())
            self.current_elements = []
            self.tree_element_map = {}
            
            # 递归构建树
            self._build_tree_from_xml_node(root, '', '')

        except Exception as e:
            self.status_var.set(f"解析XML失败: {str(e)}")
            messagebox.showerror("错误", f"解析XML失败:\n{e}")

    def _build_tree_from_xml_node(self, xml_element, parent_tree_node_id, path_prefix):
        """递归地从XML节点构建TreeView节点，并收集元素信息"""
        
        # 1. 从XML节点提取信息
        attrs = xml_element.attrib
        current_path = f"{path_prefix}/{xml_element.tag}" if path_prefix else xml_element.tag
        
        element_info = {
            'tag': xml_element.tag,
            'path': current_path,
            'bounds': attrs.get('bounds', ''),
            'bounds_info': self.parse_bounds(attrs.get('bounds', '')),
            'attributes': attrs,
            'text': attrs.get('text', ''),
            'resource-id': attrs.get('resource-id', ''),
            'content-desc': attrs.get('content-desc', ''),
            'class': attrs.get('class', ''),
            'clickable': attrs.get('clickable', 'false'),
            'checkable': attrs.get('checkable', 'false'),
            'checked': attrs.get('checked', 'false'),
            'enabled': attrs.get('enabled', 'true'),
            'focusable': attrs.get('focusable', 'false'),
            'focused': attrs.get('focused', 'false'),
            'scrollable': attrs.get('scrollable', 'false'),
            'long-clickable': attrs.get('long-clickable', 'false'),
            'password': attrs.get('password', 'false'),
            'selected': attrs.get('selected', 'false')
        }
        self.current_elements.append(element_info)

        # 2. 在TreeView中创建节点
        display_text = f"{element_info['tag']}"
        if element_info['text']:
            display_text += f" - {element_info['text'][:20]}"
        elif element_info['content-desc']:
            display_text += f" - {element_info['content-desc'][:20]}"
        elif element_info['resource-id']:
            display_text += f" - {element_info['resource-id']}"
        elif element_info['class']:
            display_text += f" - {element_info['class']}"
        
        # 3. 在TreeView中创建节点
        tree_node_id = self.elements_tree.insert(parent_tree_node_id, 'end', text=display_text, open=True)
        
        # 4. 映射TreeView节点ID和元素信息
        self.tree_element_map[tree_node_id] = element_info
        element_info['tree_node_id'] = tree_node_id

        # 5. 递归处理子节点
        for child_xml_element in xml_element:
            self._build_tree_from_xml_node(child_xml_element, tree_node_id, current_path)
    
    def parse_bounds(self, bounds_str):
        """解析bounds字符串"""
        if not bounds_str:
            return None
            
        # 格式: [x1,y1][x2,y2]
        match = re.match(r'\[(\d+),(\d+)\]\[(\d+),(\d+)\]', bounds_str)
        if match:
            x1, y1, x2, y2 = map(int, match.groups())
            return {
                'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2,
                'width': x2 - x1,
                'height': y2 - y1,
                'center_x': (x1 + x2) // 2,
                'center_y': (y1 + y2) // 2
            }
        return None
    
    def display_screenshot(self):
        """显示截图"""
        try:
            # 加载图片
            image = Image.open(self.screenshot_path)
            
            # 调整图片大小以适应画布
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            
            if canvas_width > 1 and canvas_height > 1:
                # 计算缩放比例
                img_width, img_height = image.size
                scale_x = canvas_width / img_width
                scale_y = canvas_height / img_height
                scale = min(scale_x, scale_y, 1.0)  # 不放大，只缩小
                
                new_width = int(img_width * scale)
                new_height = int(img_height * scale)
                image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
            
            # 转换为PhotoImage
            self.photo = ImageTk.PhotoImage(image)
            
            # 清除画布并显示图片
            self.canvas.delete("all")
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.photo)
            
            # 设置画布滚动区域 - 使用图片的实际尺寸
            self.canvas.configure(scrollregion=(0, 0, image.width, image.height))
            
            # 绘制元素边界
            self.draw_element_bounds()
            
        except Exception as e:
            messagebox.showerror("错误", f"显示截图失败:\n{str(e)}")
    
    def draw_element_bounds(self):
        """在截图上绘制元素边界（初始状态，较淡）"""
        if not self.current_elements:
            return
            
        # 获取图片实际尺寸
        try:
            image = Image.open(self.screenshot_path)
            img_width, img_height = image.size
            
            # 获取画布上的图片尺寸
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            
            if canvas_width <= 1 or canvas_height <= 1:
                return
                
            # 计算缩放比例
            scale_x = canvas_width / img_width
            scale_y = canvas_height / img_height
            scale = min(scale_x, scale_y, 1.0)
            
            # 绘制每个元素的边界（较淡的颜色）
            for element in self.current_elements:
                bounds = element['bounds_info']
                if bounds:
                    # 缩放坐标
                    x1 = int(bounds['x1'] * scale)
                    y1 = int(bounds['y1'] * scale)
                    x2 = int(bounds['x2'] * scale)
                    y2 = int(bounds['y2'] * scale)
                    
                    # 绘制矩形（较淡的颜色）
                    color = "lightcoral" if element.get('clickable') == 'true' else "lightblue"
                    width = 1
                    
                    self.canvas.create_rectangle(x1, y1, x2, y2, outline=color, width=width, tags="bounds")
                    
        except Exception as e:
            pass
    
    def on_canvas_click(self, event):
        """画布点击事件 - 锁定选中元素"""
        # 获取点击位置对应的元素
        clicked_element = self.find_element_at_position(event.x, event.y)
        if clicked_element:
            self.selected_element = clicked_element
            self.show_element_details(clicked_element)
            self.generate_autojs_code(clicked_element)
            # 在树形结构中定位并选中该元素
            self.highlight_element_in_tree(clicked_element)
            # 高亮显示选中的元素边界
            self.highlight_selected_element()
    
    def on_canvas_motion(self, event):
        """画布鼠标移动事件 - 悬停高亮"""
        # 高亮鼠标悬停的元素
        hover_element = self.find_element_at_position(event.x, event.y)
        if hover_element:
            self.canvas.configure(cursor="hand2")
            # 临时高亮悬停的元素
            self.highlight_hover_element(hover_element)
        else:
            self.canvas.configure(cursor="cross")
            # 清除悬停高亮
            self.clear_hover_highlight()
    
    def find_element_at_position(self, x, y):
        """查找指定位置的元素，返回面积最小（即最顶层）的那个"""
        try:
            # 检查截图文件是否存在
            if not os.path.exists(self.screenshot_path):
                return None
                
            image = Image.open(self.screenshot_path)
            img_width, img_height = image.size
            
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            
            if canvas_width <= 1 or canvas_height <= 1:
                return None
                
            # 计算缩放比例
            scale_x = canvas_width / img_width
            scale_y = canvas_height / img_height
            scale = min(scale_x, scale_y, 1.0)
            
            # 转换坐标到原始图片坐标
            original_x = int(x / scale)
            original_y = int(y / scale)
            
            # 查找所有包含该坐标的候选元素
            candidate_elements = []
            for element in self.current_elements:
                bounds = element['bounds_info']
                if bounds:
                    if (bounds['x1'] <= original_x <= bounds['x2'] and 
                        bounds['y1'] <= original_y <= bounds['y2']):
                        candidate_elements.append(element)
            
            # 从候选元素中找出面积最小的那个，即最顶层的元素
            if not candidate_elements:
                return None
            
            smallest_element = min(candidate_elements, key=lambda e: e['bounds_info']['width'] * e['bounds_info']['height'])
            return smallest_element
            
        except Exception as e:
            # 静默处理错误，不打印到控制台
            return None
    
    def on_tree_select(self, event):
        """树形结构选中事件"""
        selected_items = self.elements_tree.selection()
        if not selected_items:
            return

        node_id = selected_items[0]
        # 在我们的映射中查找元素
        element = self.tree_element_map.get(node_id)
        if element:
            self.selected_element = element
            self.show_element_details(element)
            self.generate_autojs_code(element)
            # 高亮截图上的元素边界
            self.highlight_selected_element()
            self.status_var.set(f"已选择: {element.get('class', 'N/A')} - {element.get('text', '')[:20]}")
    
    def show_element_details(self, element):
        """显示元素详细信息"""
        self.details_text.delete(1.0, tk.END)
        
        details = f"""元素详细信息:
        
标签: {element['tag']}
路径: {element['path']}
文本: {element['text']}
资源ID: {element['resource-id']}
内容描述: {element['content-desc']}
类名: {element['class']}
边界: {element['bounds']}

属性:
"""
        
        for key, value in element['attributes'].items():
            details += f"  {key}: {value}\n"
        
        if element['bounds_info']:
            bounds = element['bounds_info']
            details += f"""
边界信息:
  左上角: ({bounds['x1']}, {bounds['y1']})
  右下角: ({bounds['x2']}, {bounds['y2']})
  宽度: {bounds['width']}
  高度: {bounds['height']}
  中心点: ({bounds['center_x']}, {bounds['center_y']})
"""
        
        self.details_text.insert(1.0, details)
    
    def generate_autojs_code(self, element):
        """生成AutoJS代码"""
        self.autojs_text.delete(1.0, tk.END)
        
        if not element:
            return
        
        code = f"""// AutoJS代码 - 基于元素信息生成
// 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

// 方法1: 通过文本查找
"""
        
        if element['text']:
            code += f"""text("{element['text']}").findOne().click();
// 或者
textContains("{element['text'][:10]}").findOne().click();

"""
        
        if element['resource-id']:
            code += f"""// 方法2: 通过资源ID查找
id("{element['resource-id']}").findOne().click();

"""
        
        if element['content-desc']:
            code += f"""// 方法3: 通过内容描述查找
desc("{element['content-desc']}").findOne().click();

"""
        
        if element['class']:
            code += f"""// 方法4: 通过类名查找
className("{element['class']}").findOne().click();

"""
        
        if element['bounds_info']:
            bounds = element['bounds_info']
            code += f"""// 方法5: 通过坐标点击
click({bounds['center_x']}, {bounds['center_y']});

// 方法6: 通过坐标范围查找
bounds({bounds['x1']}, {bounds['y1']}, {bounds['x2']}, {bounds['y2']}).findOne().click();

"""
        
        # 添加更多查找方法
        code += f"""// 方法7: 组合查找
text("{element['text']}").className("{element['class']}").findOne().click();

// 方法8: 等待元素出现后点击
waitFor(() => {{
    return text("{element['text']}").exists();
}});
text("{element['text']}").findOne().click();

// 方法9: 获取元素信息
let element = text("{element['text']}").findOne();
console.log("元素文本:", element.text());
console.log("元素ID:", element.id());
console.log("元素描述:", element.desc());
console.log("元素类名:", element.className());
console.log("元素边界:", element.bounds());

"""
        
        self.autojs_text.insert(1.0, code)
    
    def copy_autojs_code(self):
        """复制AutoJS代码到剪贴板"""
        code = self.autojs_text.get(1.0, tk.END)
        if code.strip():
            self.root.clipboard_clear()
            self.root.clipboard_append(code)
            messagebox.showinfo("成功", "AutoJS代码已复制到剪贴板")
    
    def save_screenshot(self):
        """保存截图"""
        if os.path.exists(self.screenshot_path):
            filename = filedialog.asksaveasfilename(
                defaultextension=".png",
                filetypes=[("PNG文件", "*.png"), ("所有文件", "*.*")]
            )
            if filename:
                import shutil
                shutil.copy2(self.screenshot_path, filename)
                messagebox.showinfo("成功", f"截图已保存到: {filename}")
    
    def export_xml(self):
        """导出XML文件"""
        if os.path.exists(self.xml_path):
            filename = filedialog.asksaveasfilename(
                defaultextension=".xml",
                filetypes=[("XML文件", "*.xml"), ("所有文件", "*.*")]
            )
            if filename:
                import shutil
                shutil.copy2(self.xml_path, filename)
                messagebox.showinfo("成功", f"XML已导出到: {filename}")
    
    def refresh_ui(self):
        """刷新界面"""
        self.capture_screenshot()
        self.get_xml()
    
    def on_device_select(self, event):
        """设备选择事件"""
        selected_device = self.device_var.get()
        if selected_device in self.devices:
            self.current_device = selected_device
            self.adb.set_device(self.current_device)
            self.status_var.set(f"已选择设备: {selected_device}")
    
    def highlight_element_in_tree(self, element):
        """在树形结构中高亮显示指定元素"""
        # 查找对应的树节点
        for node_id, node_element in self.tree_element_map.items():
            # 通过元素的唯一标识来比较，而不是直接比较对象
            if (node_element.get('path') == element.get('path') and 
                node_element.get('bounds') == element.get('bounds') and
                node_element.get('text') == element.get('text')):
                # 选中并展开到该节点
                self.elements_tree.selection_set(node_id)
                self.elements_tree.see(node_id)
                # 展开父节点
                parent = self.elements_tree.parent(node_id)
                while parent:
                    self.elements_tree.item(parent, open=True)
                    parent = self.elements_tree.parent(parent)
                # 添加调试信息
                print(f"在树形结构中定位到元素: {element.get('tag')} - {element.get('text')}")
                break
        else:
            # 如果没有找到对应节点，添加调试信息
            print(f"未在树形结构中找到元素: {element.get('tag')} - {element.get('text')}")
            print(f"当前树形结构节点数量: {len(self.tree_element_map)}")
    
    def highlight_selected_element(self):
        """高亮显示当前选中的元素"""
        # 先清除旧的高亮
        self.clear_selection_highlight()
        
        if not self.selected_element or 'bounds_info' not in self.selected_element:
            return

        bounds = self.selected_element['bounds_info']
        if not bounds:
            return
            
        # 计算缩放比例
        try:
            image = Image.open(self.screenshot_path)
            img_width, img_height = image.size
        except FileNotFoundError:
            return # 如果截图文件不存在则不进行绘制

        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()

        if canvas_width <= 1 or canvas_height <= 1:
            return
            
        # 获取当前画布上的图片尺寸
        if self.photo:
            photo_width = self.photo.width()
            photo_height = self.photo.height()
        else:
            return # 如果没有图片则不绘制

        # 缩放比例基于原始图片和显示图片的尺寸
        scale_x = photo_width / img_width
        scale_y = photo_height / img_height
        
        x1 = int(bounds['x1'] * scale_x)
        y1 = int(bounds['y1'] * scale_y)
        x2 = int(bounds['x2'] * scale_x)
        y2 = int(bounds['y2'] * scale_y)
        
        # 绘制矩形（醒目颜色）
        self.canvas.create_rectangle(
            x1, y1, x2, y2, 
            outline="magenta", # 使用更显眼的洋红色
            width=2, 
            tags="selection_highlight"
        )
        
        # 在矩形上方显示一些信息
        text_x = x1 + 2
        text_y = y1 + 2
        self.canvas.create_text(
            text_x, text_y, 
            anchor=tk.NW, 
            text="已选中", 
            fill="magenta", # 使用更显眼的洋红色
            font=("Arial", 10, "bold"), 
            tags="selection_highlight_text"
        )
    
    def highlight_hover_element(self, element):
        """高亮显示鼠标悬停的元素边界"""
        self.clear_hover_highlight()
        if element and element.get('bounds_info'):
            bounds = element['bounds_info']
            # 获取图片实际尺寸
            try:
                image = Image.open(self.screenshot_path)
                img_width, img_height = image.size
                
                canvas_width = self.canvas.winfo_width()
                canvas_height = self.canvas.winfo_height()
                
                if canvas_width > 1 and canvas_height > 1:
                    # 计算缩放比例
                    scale_x = canvas_width / img_width
                    scale_y = canvas_height / img_height
                    scale = min(scale_x, scale_y, 1.0)
                    
                    # 缩放坐标
                    x1 = int(bounds['x1'] * scale)
                    y1 = int(bounds['y1'] * scale)
                    x2 = int(bounds['x2'] * scale)
                    y2 = int(bounds['y2'] * scale)
                    
                    # 绘制悬停高亮边框（蓝色，虚线）
                    self.canvas.create_rectangle(x1, y1, x2, y2, outline="blue", width=2, dash=(5,5), tags="hover_highlight")
                    
                    # 添加悬停标签
                    tag_name = element.get('tag', '')
                    text = element.get('text', '')[:10] if element.get('text') else element.get('resource-id', '')[:10]
                    label_text = f"{tag_name}: {text}" if text else tag_name
                    self.canvas.create_text(x1, y1-15, text=label_text, fill="blue", anchor=tk.SW, tags="hover_label")
            except Exception as e:
                pass
    
    def clear_hover_highlight(self):
        """清除悬停高亮"""
        self.canvas.delete("hover_highlight")
        self.canvas.delete("hover_label")
    
    def clear_selection_highlight(self):
        """清除选中高亮"""
        self.canvas.delete("selection_highlight")
        self.canvas.delete("selection_highlight_text")
    
    def on_closing(self):
        """窗口关闭事件处理"""
        try:
            # 清理资源
            if hasattr(self, 'photo'):
                del self.photo
            # 销毁窗口
            self.root.destroy()
            # 退出程序
            import sys
            sys.exit(0)
        except:
            pass
    
    def run(self):
        """运行应用"""
        self.root.mainloop()

def main():
    """主函数"""
    import sys
    adb_path = getattr(sys.modules[__name__], 'ADB_BIN', None)
    root = tk.Tk()
    app = AndroidUIExplorer(root, adb_path=adb_path)
    app.run()

if __name__ == "__main__":
    main() 